﻿using System;
using System.Globalization;
using AzukiMap.Map;
using AzukiMap.MapSource;
using Geometries = GisSharpBlog.NetTopologySuite.Geometries;
using GeoAPI.Geometries;
using AzukiMap.Tools;
using System.Xml.Linq;

namespace AzukiMap.Layer
{
    public class KaMapLayer : TiledLayer
    {
        private KaMapSource _kaMapSource;
        private readonly NumberFormatInfo _nfi = new NumberFormatInfo() {NumberDecimalSeparator = "."};

        public KaMapSource DataSource
        {
            get { return _kaMapSource; }
            set
            {
                _kaMapSource = value;
                MapSource = value;
            }
        }

        protected override int TileWidth
        {
            get { return _kaMapSource.TileWidth; }
        }

        public KaMapLayer()
        {
        }

        public KaMapLayer(KaMapSource mapSource, string name)
            : base(mapSource, name)
        {
            _kaMapSource = mapSource;
        }

        public KaMapLayer(KaMapSource mapSource, string name, Geometries.Polygon maxExtent)
            : base(mapSource, name, maxExtent)
        {
            _kaMapSource = mapSource;
        }

        protected override string CreateTileReqString(double tileScale, int tlX, int tlY)
        {
            string layerStr = GetLayersString();
            string groupStr = GetGroupsString();

            string tileUriStr = "?map=" + _kaMapSource.MapName + "&s=" + tileScale.ToString(_nfi)
                + "&l=" + tlX.ToString(_nfi) + "&t=" + tlY.ToString(_nfi) + "&g=" + groupStr + "&layers=" + layerStr;

            return tileUriStr;
        }

        protected override IPoint GetGeoPointFromTileCoord(int tileX, int tileY, double tileScale)
        {
            double lon = GetTileLon(tileX, tileScale);
            double lat = GetTileLat(tileY, tileScale);

            return new Geometries.Point(lon, lat) {SRID = this.Srid};
            /*
            ICoordinate geoPoint = new Geometries.Coordinate(lon, lat);

            return geoPoint;
             */
        }

        protected override ICoordinate GetTileOriginFromMapCenter(IPoint point, double tileScale)
        {
            IPoint p = TransformUtil.Transform(point, Srid);
            int originX = GetTileOriginX(p.X, tileScale);
            int originY = GetTileOriginY(p.Y, tileScale);

            ICoordinate tileOrigin = new Geometries.Coordinate(originX, originY);

            return tileOrigin;
        }

        protected int GetTileOriginX(double lon, double tileScale)
        {
            double pixelPerUnit = GetPixelPerUnit(tileScale);
            int tileXNum = (int)Math.Floor(lon * pixelPerUnit / _kaMapSource.TileWidth);
            return _kaMapSource.TileWidth * tileXNum;
        }

        protected int GetTileOriginY(double lat, double tileScale)
        {
            double pixelPerUnit = GetPixelPerUnit(tileScale);
            int flip = (MapCoord.FlipY) ? -1 : 1;
            int tileYNum = (int)Math.Floor(lat * pixelPerUnit / _kaMapSource.TileHeight) * flip;
            return _kaMapSource.TileHeight * tileYNum;
        }

        double GetTileLon(int tileX, double tileScale)
        {
            double pixelPerUnit = GetPixelPerUnit(tileScale);
            return (double)tileX / pixelPerUnit;
        }

        double GetTileLat(int tileY, double tileScale)
        {
            double pixelPerUnit = GetPixelPerUnit(tileScale);
            int flip = (MapCoord.FlipY) ? -1 : 1;
            return (double)tileY / pixelPerUnit * flip;
        }

        string GetLayersString()
        {
            string layerString = "";
            string splitter = "";
            foreach (string layer in _kaMapSource.Layers)
            {
                layerString += layer + splitter;
                splitter = ",";
            }
            return layerString;
        }

        string GetGroupsString()
        {
            string groupString = "";
            string splitter = "";
            foreach (string group in _kaMapSource.Groups)
            {
                groupString += group + splitter;
                splitter = ",";
            }
            return groupString;
        }


        public override System.Xml.Linq.XElement ToXml()
        {
            return ToXml("KaMapLayer");
        }

        public override XElement ToXml(string elementName)
        {
            XElement element = base.ToXml(elementName);
            element.Add(_kaMapSource.ToXml("KaMapSource"));

            return element;
        }

        public override void Parse(XElement xmlSource)
        {
            base.Parse(xmlSource);
            DataSource = new KaMapSource();
            DataSource.Parse(xmlSource.Element("KaMapSource"));
        }
    }
}
